package com.lei.springbootpractice.service;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

/**
 * 图片处理服务
 * 用于处理商品图片的上传、压缩和Base64编码
 */
@Service
public class ImageService {

    // 最大图片尺寸
    private static final int MAX_WIDTH = 800;
    private static final int MAX_HEIGHT = 600;
    
    // 支持的图片格式
    private static final String[] SUPPORTED_FORMATS = {"jpg", "jpeg", "png", "gif", "bmp"};
    
    // 最大文件大小（5MB）
    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024;

    /**
     * 将上传的图片转换为Base64编码
     * @param file 上传的图片文件
     * @return Base64编码的图片数据，格式为 "data:image/jpeg;base64,..."
     * @throws IOException 处理失败时抛出异常
     */
    public String convertImageToBase64(MultipartFile file) throws IOException {
        // 验证文件
        validateImage(file);
        
        // 压缩图片
        byte[] compressedImageData = compressImage(file);
        
        // 转换为Base64
        String base64Data = Base64.getEncoder().encodeToString(compressedImageData);
        
        // 获取MIME类型
        String contentType = file.getContentType();
        if (contentType == null) {
            contentType = "image/jpeg"; // 默认类型
        }
        
        // 返回完整的data URL格式
        return "data:" + contentType + ";base64," + base64Data;
    }

    /**
     * 验证上传的图片文件
     */
    private void validateImage(MultipartFile file) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IOException("图片文件不能为空");
        }
        
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new IOException("图片文件大小不能超过 5MB");
        }
        
        String fileName = file.getOriginalFilename();
        if (fileName == null || !isValidImageFormat(fileName)) {
            throw new IOException("不支持的图片格式，请上传 JPG、PNG、GIF 或 BMP 格式的图片");
        }
        
        String contentType = file.getContentType();
        if (contentType == null || !contentType.startsWith("image/")) {
            throw new IOException("上传的文件不是有效的图片格式");
        }
    }

    /**
     * 检查是否为支持的图片格式
     */
    private boolean isValidImageFormat(String fileName) {
        String extension = getFileExtension(fileName).toLowerCase();
        for (String format : SUPPORTED_FORMATS) {
            if (format.equals(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return "";
        }
        return fileName.substring(lastDotIndex + 1);
    }

    /**
     * 压缩图片
     */
    private byte[] compressImage(MultipartFile file) throws IOException {
        // 读取原始图片
        BufferedImage originalImage = ImageIO.read(file.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件，请确保文件未损坏");
        }
        
        // 计算压缩后的尺寸
        Dimension newSize = calculateCompressedSize(
            originalImage.getWidth(), 
            originalImage.getHeight()
        );
        
        // 如果图片尺寸已经很小，不需要压缩
        if (newSize.width == originalImage.getWidth() && 
            newSize.height == originalImage.getHeight()) {
            return file.getBytes();
        }
        
        // 创建压缩后的图片
        BufferedImage compressedImage = new BufferedImage(
            newSize.width, 
            newSize.height, 
            BufferedImage.TYPE_INT_RGB
        );
        
        // 使用高质量的图片缩放算法
        Graphics2D g2d = compressedImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        g2d.drawImage(originalImage, 0, 0, newSize.width, newSize.height, null);
        g2d.dispose();
        
        // 转换为字节数组
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        String format = getImageFormat(file.getContentType());
        ImageIO.write(compressedImage, format, outputStream);
        
        return outputStream.toByteArray();
    }

    /**
     * 计算压缩后的图片尺寸（保持宽高比）
     */
    private Dimension calculateCompressedSize(int originalWidth, int originalHeight) {
        if (originalWidth <= MAX_WIDTH && originalHeight <= MAX_HEIGHT) {
            return new Dimension(originalWidth, originalHeight);
        }
        
        double widthRatio = (double) MAX_WIDTH / originalWidth;
        double heightRatio = (double) MAX_HEIGHT / originalHeight;
        double ratio = Math.min(widthRatio, heightRatio);
        
        int newWidth = (int) (originalWidth * ratio);
        int newHeight = (int) (originalHeight * ratio);
        
        return new Dimension(newWidth, newHeight);
    }

    /**
     * 根据MIME类型获取图片格式
     */
    private String getImageFormat(String contentType) {
        if (contentType == null) {
            return "jpg";
        }
        
        switch (contentType.toLowerCase()) {
            case "image/png":
                return "png";
            case "image/gif":
                return "gif";
            case "image/bmp":
                return "bmp";
            default:
                return "jpg";
        }
    }

    /**
     * 从Base64数据中提取图片字节数组（用于BLOB存储方案）
     */
    public byte[] base64ToBytes(String base64Data) throws IOException {
        try {
            // 移除data URL前缀
            if (base64Data.startsWith("data:")) {
                int commaIndex = base64Data.indexOf(',');
                if (commaIndex != -1) {
                    base64Data = base64Data.substring(commaIndex + 1);
                }
            }
            
            return Base64.getDecoder().decode(base64Data);
        } catch (IllegalArgumentException e) {
            throw new IOException("无效的Base64图片数据", e);
        }
    }

    /**
     * 验证Base64图片数据
     */
    public boolean isValidBase64Image(String base64Data) {
        if (base64Data == null || base64Data.trim().isEmpty()) {
            return false;
        }
        
        try {
            // 检查是否为data URL格式
            if (!base64Data.startsWith("data:image/")) {
                return false;
            }
            
            // 尝试解码
            byte[] imageBytes = base64ToBytes(base64Data);
            
            // 尝试读取图片
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
            return image != null;
            
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取Base64图片的大小信息
     */
    public ImageInfo getImageInfo(String base64Data) throws IOException {
        byte[] imageBytes = base64ToBytes(base64Data);
        BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
        
        if (image == null) {
            throw new IOException("无法读取图片数据");
        }
        
        return new ImageInfo(
            image.getWidth(),
            image.getHeight(),
            imageBytes.length
        );
    }

    /**
     * 图片信息类
     */
    public static class ImageInfo {
        private final int width;
        private final int height;
        private final int fileSize;

        public ImageInfo(int width, int height, int fileSize) {
            this.width = width;
            this.height = height;
            this.fileSize = fileSize;
        }

        public int getWidth() { return width; }
        public int getHeight() { return height; }
        public int getFileSize() { return fileSize; }
        
        public String getFileSizeFormatted() {
            if (fileSize < 1024) {
                return fileSize + " B";
            } else if (fileSize < 1024 * 1024) {
                return String.format("%.1f KB", fileSize / 1024.0);
            } else {
                return String.format("%.1f MB", fileSize / (1024.0 * 1024.0));
            }
        }
    }
} 